From ac9621badb8b5d068d3c0fac9b01c3bd67794ac1 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sat, 15 May 2004 00:29:39 +0000 Subject: [PATCH] Add categorylinks table to separately list category relationships. Actual _page_ links to category pages like [[:category:Some cat]] will stay in links/brokenlinks and not be listed in the category page list anymore. A link can optionally specify a sort key like this: [[category:cat|Sort me]]. The page will then be sorted in category lists according to the given text instead of the page name; thus categories may be sorted arbitrarily, by last name or whatever. There is also a timestamp field included on gwicke's request; this is not used yet. Also it will currently be updated at every edit of the page, this can be changed by implementing differential updating for the cat links. TODO: * Make sure that automatic sort keys are updated on page rename. * Make sure cateory pages get cache-invalidated and purged * Use proper text sorting instead of raw binary sort * Allow specification of the display style on category pages: comma list or bullet list or number list; by sortkey or by timestamp; etc --- config/index.php | 1 + includes/Article.php | 3 + includes/LinkCache.php | 14 ++++- includes/LinksUpdate.php | 61 +++++++++++++++++++- includes/Parser.php | 40 ++++++------- maintenance/archives/patch-categorylinks.sql | 15 +++++ maintenance/archives/patch-list.txt | 3 + maintenance/tables.sql | 16 +++++ maintenance/updaters.inc | 11 ++++ 9 files changed, 138 insertions(+), 26 deletions(-) create mode 100644 maintenance/archives/patch-categorylinks.sql diff --git a/config/index.php b/config/index.php index 907856af73..2c189a48ba 100644 --- a/config/index.php +++ b/config/index.php @@ -403,6 +403,7 @@ if( $conf->posted && ( 0 == count( $errs ) ) ) { do_user_real_name_update(); flush(); do_querycache_update(); flush(); do_objectcache_update(); flush(); + do_categorylinks_update(); flush(); initialiseMessages(); flush(); chdir( "config" ); diff --git a/includes/Article.php b/includes/Article.php index dd1b38d4e2..6ccdb7bb2a 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -1282,6 +1282,9 @@ class Article { $sql = "DELETE FROM brokenlinks WHERE bl_from={$id}"; wfQuery( $sql, DB_WRITE, $fname ); + $sql = "DELETE FROM categorylinks WHERE cl_from={$id}"; + wfQuery( $sql, DB_WRITE, $fname ); + $log = new LogPage( wfMsg( "dellogpage" ), wfMsg( "dellogpagetext" ) ); $art = $this->mTitle->getPrefixedText(); $log->addEntry( wfMsg( "deletedarticle", $art ), $reason ); diff --git a/includes/LinkCache.php b/includes/LinkCache.php index 0c50c7d2f7..8f41cccf7e 100644 --- a/includes/LinkCache.php +++ b/includes/LinkCache.php @@ -9,10 +9,10 @@ define ('LINKCACHE_IMAGE', 2); class LinkCache { // Increment $mClassVer whenever old serialized versions of this class // becomes incompatible with the new version. - /* private */ var $mClassVer = 1; + /* private */ var $mClassVer = 2; /* private */ var $mGoodLinks, $mBadLinks, $mActive; - /* private */ var $mImageLinks; + /* private */ var $mImageLinks, $mCategoryLinks; /* private */ var $mPreFilled, $mOldGoodLinks, $mOldBadLinks; /* private */ function getKey( $title ) { @@ -27,6 +27,7 @@ class LinkCache { $this->mGoodLinks = array(); $this->mBadLinks = array(); $this->mImageLinks = array(); + $this->mCategoryLinks = array(); $this->mOldGoodLinks = array(); $this->mOldBadLinks = array(); } @@ -68,6 +69,14 @@ class LinkCache { { if ( $this->mActive ) { $this->mImageLinks[$nt->getDBkey()] = 1; } } + + function addCategoryLink( $title, $sortkey ) { + if ( $this->mActive ) { $this->mCategoryLinks[$title] = $sortkey; } + } + + function addCategoryLinkObj( &$nt, $sortkey ) { + $this->addCategoryLink( $nt->getDBkey(), $sortkey ); + } function clearBadLink( $title ) { @@ -87,6 +96,7 @@ class LinkCache { function getGoodLinks() { return $this->mGoodLinks; } function getBadLinks() { return array_keys( $this->mBadLinks ); } function getImageLinks() { return $this->mImageLinks; } + function getCategoryLinks() { return $this->mCategoryLinks; } function addLink( $title ) { diff --git a/includes/LinksUpdate.php b/includes/LinksUpdate.php index fe39d36563..104e442471 100644 --- a/includes/LinksUpdate.php +++ b/includes/LinksUpdate.php @@ -16,7 +16,7 @@ class LinksUpdate { function doUpdate() { global $wgUseBetterLinksUpdate, $wgLinkCache, $wgDBtransactions; - global $wgEnablePersistentLC; + global $wgEnablePersistentLC, $wgUseCategoryMagic; /* Update link tables with outgoing links from an updated article */ /* Relies on the 'link cache' to be filled out */ @@ -133,6 +133,36 @@ class LinksUpdate { } if ( "" != $sql ) { wfQuery( $sql, DB_WRITE, $fname ); } + #------------------------------------------------------------------------------ + # Category links + if( $wgUseCategoryMagic ) { + $sql = "DELETE FROM categorylinks WHERE cl_from='{$this->mId}'"; + wfQuery( $sql, DB_WRITE, $fname ); + + # Get addition list + $add = $wgLinkCache->getCategoryLinks(); + + # Do the insertion + $sql = ""; + if ( 0 != count ( $add ) ) { + $sql = "INSERT INTO categorylinks (cl_from,cl_to,cl_sortkey) VALUES "; + $first = true; + foreach( $add as $cname => $sortkey ) { + # FIXME: Change all this to avoid unnecessary duplication + $nt = Title::makeTitle( NS_CATEGORY, $cname ); + if( !$nt ) continue; + $nt->invalidateCache(); + + if ( ! $first ) { $sql .= ","; } + $first = false; + + $sql .= "({$this->mId},'" . wfStrencode( $cname ) . + "','" . wfStrencode( $sortkey ) . "')"; + } + } + if ( "" != $sql ) { wfQuery( $sql, DB_WRITE, $fname ); } + } + $this->fixBrokenLinks(); if( $wgDBtransactions ) { @@ -147,7 +177,7 @@ class LinksUpdate { # Old inefficient update function # Used for rebuilding the link table - global $wgLinkCache, $wgDBtransactions; + global $wgLinkCache, $wgDBtransactions, $wgUseCategoryMagic; $fname = "LinksUpdate::doDumbUpdate"; wfProfileIn( $fname ); @@ -209,6 +239,33 @@ class LinksUpdate { } if ( "" != $sql ) { wfQuery( $sql, DB_WRITE, $fname ); } + if( $wgUseCategoryMagic ) { + $sql = "DELETE FROM categorylinks WHERE cl_from='{$this->mId}'"; + wfQuery( $sql, DB_WRITE, $fname ); + + # Get addition list + $add = $wgLinkCache->getCategoryLinks(); + + # Do the insertion + $sql = ""; + if ( 0 != count ( $add ) ) { + $sql = "INSERT INTO categorylinks (cl_from,cl_to,cl_sortkey) VALUES "; + $first = true; + foreach( $add as $cname => $sortkey ) { + # FIXME: Change all this to avoid unnecessary duplication + $nt = Title::makeTitle( NS_CATEGORY, $cname ); + if( !$nt ) continue; + $nt->invalidateCache(); + + if ( ! $first ) { $sql .= ","; } + $first = false; + + $sql .= "({$this->mId},'" . wfStrencode( $cname ) . + "','" . wfStrencode( $sortkey ) . "')"; + } + } + if ( "" != $sql ) { wfQuery( $sql, DB_WRITE, $fname ); } + } $this->fixBrokenLinks(); if( $wgDBtransactions ) { diff --git a/includes/Parser.php b/includes/Parser.php index e292278267..c345e28eec 100644 --- a/includes/Parser.php +++ b/includes/Parser.php @@ -316,18 +316,11 @@ class Parser $data = array () ; $id = $this->mTitle->getArticleID() ; - # For existing categories - if( $id ) { - $sql = "SELECT DISTINCT cur_title,cur_namespace FROM cur,links WHERE l_to={$id} AND l_from=cur_id"; - $res = wfQuery ( $sql, DB_READ ) ; - while ( $x = wfFetchObject ( $res ) ) $data[] = $x ; - } else { - # For non-existing categories - $t = wfStrencode( $this->mTitle->getPrefixedDBKey() ); - $sql = "SELECT DISTINCT cur_title,cur_namespace FROM cur,brokenlinks WHERE bl_to='$t' AND bl_from=cur_id" ; - $res = wfQuery ( $sql, DB_READ ) ; - while ( $x = wfFetchObject ( $res ) ) $data[] = $x ; - } + # FIXME: add limits + $t = wfStrencode( $this->mTitle->getDBKey() ); + $sql = "SELECT DISTINCT cur_title,cur_namespace FROM cur,categorylinks WHERE cl_to='$t' AND cl_from=cur_id ORDER BY cl_sortkey" ; + $res = wfQuery ( $sql, DB_READ ) ; + while ( $x = wfFetchObject ( $res ) ) $data[] = $x ; # For all pages that link to this category foreach ( $data AS $x ) @@ -345,18 +338,14 @@ class Parser wfFreeResult ( $res ) ; # Showing subcategories - if ( count ( $children ) > 0 ) - { - asort ( $children ) ; + if ( count ( $children ) > 0 ) { $r .= "

".wfMsg("subcategories")."

\n" ; $r .= implode ( ", " , $children ) ; } # Showing pages in this category - if ( count ( $articles ) > 0 ) - { + if ( count ( $articles ) > 0 ) { $ti = $this->mTitle->getText() ; - asort ( $articles ) ; $h = wfMsg( "category_header", $ti ); $r .= "

{$h}

\n" ; $r .= implode ( ", " , $articles ) ; @@ -570,9 +559,9 @@ class Parser $text = $sk->transformContent( $text ); if ( !isset ( $this->categoryMagicDone ) ) { - $text .= $this->categoryMagic () ; - $this->categoryMagicDone = true ; - } + $text .= $this->categoryMagic () ; + $this->categoryMagicDone = true ; + } wfProfileOut( $fname ); return $text; @@ -1021,7 +1010,8 @@ class Parser } else { $link = substr( $m[1], 1 ); } - if( "" == $text ) + $wasblank = ( "" == $text ); + if( $wasblank ) $text = $link; $nt = Title::newFromText( $link ); @@ -1045,7 +1035,13 @@ class Parser if ( $ns == $category ) { $t = $nt->getText() ; $nnt = Title::newFromText ( Namespace::getCanonicalName($category).":".$t ) ; + + $wgLinkCache->suspend(); # Don't save in links/brokenlinks $t = $sk->makeLinkObj( $nnt, $t, "", "" , $prefix ); + $wgLinkCache->resume(); + + $sortkey = $wasblank ? $this->mTitle->getPrefixedText() : $text; + $wgLinkCache->addCategoryLinkObj( $nt, $sortkey ); $this->mOutput->mCategoryLinks[] = $t ; $s .= $prefix . $trail ; return $s ; diff --git a/maintenance/archives/patch-categorylinks.sql b/maintenance/archives/patch-categorylinks.sql new file mode 100644 index 0000000000..962a0ad4eb --- /dev/null +++ b/maintenance/archives/patch-categorylinks.sql @@ -0,0 +1,15 @@ +-- +-- Track category inclusions *used inline* +-- cl_from keys to cur_id, cl_to keys to cur_title of the category page. +-- cl_sortkey is the title of the linking page or an optional override +-- cl_timestamp marks when the link was last added +-- +CREATE TABLE categorylinks ( + cl_from int(8) unsigned NOT NULL default '0', + cl_to varchar(255) binary NOT NULL default '', + cl_sortkey varchar(255) binary NOT NULL default '', + cl_timestamp timestamp NOT NULL, + UNIQUE KEY cl_from(cl_from,cl_to), + KEY cl_sortkey(cl_to,cl_sortkey(128)), + KEY cl_timestamp(cl_to,cl_timestamp) +); diff --git a/maintenance/archives/patch-list.txt b/maintenance/archives/patch-list.txt index 258567289a..93a63bfd18 100644 --- a/maintenance/archives/patch-list.txt +++ b/maintenance/archives/patch-list.txt @@ -177,3 +177,6 @@ patch-user-realname.sql object cache to cover some slow operations w/o memcached. patch-querycache.sql patch-objectcache.sql + +* 2004-05-14: Add categorylinks table for handling category membership +patch-categorylinks.sql diff --git a/maintenance/tables.sql b/maintenance/tables.sql index 3e15e1d836..d149298dbc 100644 --- a/maintenance/tables.sql +++ b/maintenance/tables.sql @@ -104,6 +104,22 @@ CREATE TABLE imagelinks ( KEY (il_to) ); +-- +-- Track category inclusions *used inline* +-- cl_from keys to cur_id, cl_to keys to cur_title of the category page. +-- cl_sortkey is the title of the linking page or an optional override +-- cl_timestamp marks when the link was last added +-- +CREATE TABLE categorylinks ( + cl_from int(8) unsigned NOT NULL default '0', + cl_to varchar(255) binary NOT NULL default '', + cl_sortkey varchar(255) binary NOT NULL default '', + cl_timestamp timestamp NOT NULL, + UNIQUE KEY cl_from(cl_from,cl_to), + KEY cl_sortkey(cl_to,cl_sortkey(128)), + KEY cl_timestamp(cl_to,cl_timestamp) +); + -- -- Stores (possibly gzipped) serialized objects with -- cache arrays to reduce database load slurping up diff --git a/maintenance/updaters.inc b/maintenance/updaters.inc index 9509c0a8fb..d557ebb5e8 100644 --- a/maintenance/updaters.inc +++ b/maintenance/updaters.inc @@ -156,4 +156,15 @@ function do_objectcache_update() { } } +function do_categorylinks_update() { + global $wgDatabase; + if( $wgDatabase->tableExists( "categorylinks" ) ) { + echo "...have categorylinks table.\n"; + } else { + echo "Adding categorylinks table for category management... "; + dbsource( "maintenance/archives/patch-categorylinks.sql", $wgDatabase ); + echo "ok\n"; + } +} + ?> \ No newline at end of file -- 2.20.1